package com.example.usercenter.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.usercenter.common.ErrorCode;
import com.example.usercenter.common.Result;
import com.example.usercenter.common.ResultUtils;
import com.example.usercenter.exception.ServiceException;
import com.example.usercenter.model.domain.User;
import com.example.usercenter.model.request.UserLoginRequest;
import com.example.usercenter.model.request.UserRegisterRequest;
import com.example.usercenter.service.UserService;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.description.method.MethodDescription;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.example.usercenter.constants.UserConstant.USER_EXPIRES_TIME;
import static com.example.usercenter.constants.UserConstant.USER_KEY_PREFIX;


@Slf4j
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {
    @Resource
    private UserService userService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostMapping("/register")
    public Result<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        // 1. 参数校验
        if (userRegisterRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 注册逻辑校验
        String account = userRegisterRequest.getUserAccount();
        String pwd = userRegisterRequest.getUserPassword();
        String rePwd = userRegisterRequest.getUserRePassword();
        long registerRes = userService.userRegister(account, pwd, rePwd);
        return ResultUtils.success(registerRes);
    }

    @PostMapping("/login")
    public Result<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
        // 1. 校验参数
        if (userLoginRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 调用service层逻辑
        String account = userLoginRequest.getUserAccount();
        String pwd = userLoginRequest.getUserPassword();
        log.info("接收到用户登录请求：用户名：" + account + ",密码：" + pwd);
        User loginUser = userService.userLogin(account, pwd, request);
        return ResultUtils.success(loginUser);
    }

    /**
     * 根据用户名模糊查询所有用户
     * @param username 用户名
     * @return 用户列表
     */
    @GetMapping("/getAll")
    public Result<List<User>> getUsers(String username, HttpSession session) {
        // 0. 权限验证
        if (!userService.isAdmin(session)) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        // 1. 校验参数是否为空
        if (StringUtils.isBlank(username)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 查询用户
        List<User> users = userService.getUsesByUsername(username);
        users.stream().map((ele) -> {
            ele.setUserPassword("");
            ele.setCreateTime(null);
            ele.setUpdateTime(null);
            return ele;
        }).collect(Collectors.toList());
        return ResultUtils.success(users);
    }

    /**
     * 查询所有用户
     * @return 用户列表
     */
    @GetMapping("/search")
    public Result<List<User>> getAllUsers(HttpSession session) {
        // 0. TODO：权限验证
//        if (!isAdmin(session)) {
//            return new ArrayList<>();
//        }
        // 1. 查询用户
        List<User> users = userService.list();
        users.stream().map((ele) -> {
            ele.setUserPassword("");
            ele.setUpdateTime(null);
            return ele;
        }).collect(Collectors.toList());
        return ResultUtils.success(users);
    }

    /**
     * 删除用户
     * @param userId 用户id
     * @return true: 删除成功，false: 删除失败
     */
    @PostMapping("/del")
    public Result<Boolean> deleteUser(Integer userId, HttpSession session) {
        // 0. 权限验证
        if (!userService.isAdmin(session)) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        // 1. 字段验证
        if (ObjectUtils.isEmpty(userId)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 进行删除
        boolean delRes = userService.deleteUserById(userId);
        return ResultUtils.success(delRes);
    }

    /**
     * 获取当前登录用户
     * @return 当前登录用户
     */
    @GetMapping("/current")
    public Result<User> getCurrentUser(HttpSession session) {
        log.info("调用获取当前登陆用户接口...");
        // 1. 获取当前登录用户
        User loginUser = userService.getLoginUser(session);
        // 2. 返回信息（从数据库中查询）
        User dbUser = userService.getById(loginUser.getId());
        return ResultUtils.success(dbUser);
    }

    /**
     * 根据标签列表查询匹配用户
     * @param tagNameList
     * @return
     */
    @GetMapping("/search/tag")
    public Result<List<User>> matchUsersByTagList(@RequestParam(required = false) List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        List<User> matchUsers = userService.matchUsersByTagName(tagNameList);
        return ResultUtils.success(matchUsers);
    }

    @PostMapping("/edit")
    public Result<Boolean> editUser(@RequestBody User user, HttpSession session) {
        // 1. 参数校验
        if (user == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 调用编辑逻辑
        boolean editTRes = userService.editUser(user, session);
        return ResultUtils.success(editTRes);
    }

    /**
     * 推荐用户功能（Redis缓存）
     * @param pageNum 分页数
     * @param pageSize 分页尺寸
     * @return 推荐用户列表
     */
    @GetMapping("/recommend")
    public Result<List<User>> getRecommendUsers(@RequestParam(required = false, defaultValue = "1") Long pageNum, @RequestParam(required = false, defaultValue = "10") Long pageSize, HttpSession session) {
        // 1. 获取当前登录用户
        User loginUser = userService.getLoginUser(session);
        long loginUserId = loginUser.getId();
        // 2. 查询缓存
        String cacheKey = USER_KEY_PREFIX + loginUserId;
        String res = redisTemplate.opsForValue().get(cacheKey);
        Gson gson = new Gson();
        if (StringUtils.isNotBlank(res)) {
            // 2.1 缓存命中直接返回
            List<User> cacheUserList = gson.fromJson(res, new TypeToken<List<User>>() {}.getType());
            return ResultUtils.success(cacheUserList);
        }
        // 2.2 缓存没有命中就查数据库
        List<User> dbUserList = userService.page(new Page<>(pageNum, pageSize)).getRecords();
        // 脱敏处理
        List<User> safeUserList = dbUserList
                .stream()
                .map(dbUser -> userService.getSafetyUser(dbUser))
                .collect(Collectors.toList());
        // 写入缓存
        String cacheUserListStr = gson.toJson(safeUserList);
        redisTemplate.opsForValue().set(cacheKey, cacheUserListStr, USER_EXPIRES_TIME, TimeUnit.MINUTES); // 设置过期时间
        return ResultUtils.success(safeUserList);
    }

    /**
     * 推荐与登录用户匹配度最高的前num个用户
     * @param num 推荐用户数
     * @return 推荐用户列表（根据相似度从高到低排序）
     */
    @GetMapping("/match")
    public Result<List<User>> matchUsers(@RequestParam(required = false, defaultValue = "10") int num, HttpSession session) {
        // 1. 校验用户登录态
        try {
            User loginUser = userService.getLoginUser(session);
            // 2. 调用业务层进行匹配运算
            List<User> matchUserList = userService.matchUserList(num, loginUser);
            return ResultUtils.success(matchUserList);
        } catch (Exception e) {
            // 没有登录直接返回数据库前num个用户
            return ResultUtils.success(userService
                    .page(new Page<User>(1, num))
                    .getRecords());
        }


    }
}
